﻿using System;
using System.Collections.Generic;
using System.Text;
using EmbeddedSharp.Core.Function.Arithmetics;
using EmbeddedSharp.Core.Function.Maths;

namespace EmbeddedSharp.Core {
    public class CSharpExpressionTranslator : IExpressionTranslator, IVisitor {

        private Node root = null;

        public Dictionary<string, string> Rpl {
            get;
            set;
        }

        public CSharpExpressionTranslator() {

        }

        public string Translate(Node node) {
            return Convert.ToString(node.Accept(this));
        }

        public object VisitOperator(OperatorNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append(node.Value).Append(r).Append(")").ToString();
        }

        public object Visit(AddNode node) {
            return VisitOperator(node);
        }

        public object Visit(SubNode node) {
            return VisitOperator(node);
        }

        public object Visit(ModNode node) {
            return VisitOperator(node);
        }

        public object Visit(MulNode node) {
            return VisitOperator(node);
        }

        public object Visit(DivNode node) {
            return VisitOperator(node);
        }

        public object Visit(IdentifierNode node) {
            return node.Value;
        }

        public object Visit(NumberNode node) {
            return node.Value;
        }

        public object Visit(PowerNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("Math.Pow(").Append(l).Append(",").Append(r).Append(")").ToString();
        }

        public object Visit(LogNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("Math.Log(").Append(l).Append(",").Append(r).Append(")").ToString();
        }

        public object Visit(FuncNode node) {
            StringBuilder buff = new StringBuilder();

            bool first = true;
            buff.Append(GetFunctionName(node.Value)).Append("(");
            foreach (Node child in node.Parameters) {
                if (!first) {
                    buff.Append(",");
                }
                first = false;

                string t = Convert.ToString(child.Accept(this));
                buff.Append(t);
            }
            buff.Append(")");

            return buff.ToString();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="funcName"></param>
        /// <returns></returns>
        public static string GetFunctionName(string funcName) {
            return "Math." + char.ToUpper(funcName[0]) + funcName.Substring(1, funcName.Length - 1);
        }

        public object Visit(EmbeddedSharp.Core.StringNode node) {
            return node.Value;
        }

        public object Visit(EmbeddedSharp.Core.Function.Logic.LargerThanNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append(">").Append(r).Append(")").ToString();
        }

        public object Visit(EmbeddedSharp.Core.Function.Logic.LessThanNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append("<").Append(r).Append(")").ToString();
        }

        public object Visit(EmbeddedSharp.Core.Function.Logic.LargerEqualToNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append(">=").Append(r).Append(")").ToString();
        }

        public object Visit(EmbeddedSharp.Core.Function.Logic.LessEqualToNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append("<=").Append(r).Append(")").ToString();
        }

        public object Visit(EmbeddedSharp.Core.Function.Logic.EqualNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append("==").Append(r).Append(")").ToString();
        }

        public object Visit(EmbeddedSharp.Core.Function.Logic.NotEqualNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append("!=").Append(r).Append(")").ToString();
        }

        public object Visit(EmbeddedSharp.Core.Function.Logic.AndNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append(" && ").Append(r).Append(")").ToString();
        }

        public object Visit(EmbeddedSharp.Core.Function.Logic.OrNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Left.Accept(this));
            string r = Convert.ToString(node.Right.Accept(this));

            return buff.Append("(").Append(l).Append(" || ").Append(r).Append(")").ToString();
        }

        public object Visit(EmbeddedSharp.Core.Function.Logic.NotNode node) {
            StringBuilder buff = new StringBuilder();

            string l = Convert.ToString(node.Operand.Accept(this));

            return buff.Append("(!").Append(l).Append(")").ToString();
        }
    }
}
